package org.example.lethear.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.lethear.dto.common.PageResult;
import org.example.lethear.dto.file.FileDTO;
import org.example.lethear.dto.file.FileUploadResponse;
import org.example.lethear.entity.File;
import org.example.lethear.entity.User;
import org.example.lethear.exception.BusinessException;
import org.example.lethear.exception.ResourceNotFoundException;
import org.example.lethear.repository.FileRepository;
import org.example.lethear.repository.UserRepository;
import org.example.lethear.utils.Result;
import org.example.lethear.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 文件管理控制器
 */
@Tag(name = "文件管理", description = "文件上传、下载、删除等相关接口")
@RestController
@RequestMapping("/files")
@RequiredArgsConstructor
@Slf4j
public class FileController {
    
    private final FileRepository fileRepository;
    private final UserRepository userRepository;
    
    @Value("${file.upload-dir:./uploads/}")
    private String uploadDir;
    
    @Value("${file.max-size:10485760}")
    private long maxFileSize;
    
    /**
     * 上传文件
     */
    @Operation(summary = "上传文件", description = "上传文件到服务器")
    @PostMapping("/upload")
    @Transactional
    public Result<FileUploadResponse> uploadFile(
            @Parameter(description = "文件") @RequestParam("file") MultipartFile file,
            @Parameter(description = "上传类型") @RequestParam(value = "uploadType", defaultValue = "general") String uploadType) {
        
        Long currentUserId = SecurityUtils.getCurrentUserId();
        if (currentUserId == null) {
            throw new BusinessException("用户未登录");
        }
        
        if (file.isEmpty()) {
            throw new BusinessException("文件不能为空");
        }
        
        if (file.getSize() > maxFileSize) {
            throw new BusinessException("文件大小不能超过" + (maxFileSize / 1024 / 1024) + "MB");
        }
        
        try {
            // 创建上传目录
            Path uploadPath = Paths.get(uploadDir);
            if (!Files.exists(uploadPath)) {
                Files.createDirectories(uploadPath);
            }
            
            // 生成文件名
            String originalFilename = file.getOriginalFilename();
            String fileExtension = "";
            if (originalFilename != null && originalFilename.contains(".")) {
                fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            }
            
            String fileName = UUID.randomUUID().toString() + fileExtension;
            String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
            Path dateDir = uploadPath.resolve(datePath);
            
            if (!Files.exists(dateDir)) {
                Files.createDirectories(dateDir);
            }
            
            Path filePath = dateDir.resolve(fileName);
            
            // 保存文件
            Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
            
            // 保存文件记录
            File fileEntity = new File();
            fileEntity.setUserId(currentUserId);
            fileEntity.setFilename(fileName);
            fileEntity.setOriginalName(originalFilename);
            fileEntity.setFilePath(filePath.toString());
            fileEntity.setFileSize(file.getSize());
            fileEntity.setFileType(getFileType(fileExtension));
            
            fileEntity = fileRepository.save(fileEntity);
            
            // 构建响应
            FileUploadResponse response = FileUploadResponse.builder()
                    .id(fileEntity.getId())
                    .fileName(fileName)
                    .originalName(originalFilename)
                    .fileType(fileEntity.getFileType())
                    .fileSize(file.getSize())
                    .fileUrl("/api/files/download/" + fileEntity.getId())
                    .uploadType(uploadType)
                    .createdAt(fileEntity.getCreateTime())
                    .success(true)
                    .message("文件上传成功")
                    .build();
            
            log.info("文件上传成功: {} -> {}", originalFilename, fileName);
            
            return Result.success("文件上传成功", response);
            
        } catch (IOException e) {
            log.error("文件上传失败", e);
            throw new BusinessException("文件上传失败: " + e.getMessage());
        }
    }
    
    /**
     * 下载文件
     */
    @Operation(summary = "下载文件", description = "根据文件ID下载文件")
    @GetMapping("/download/{fileId}")
    public ResponseEntity<Resource> downloadFile(@Parameter(description = "文件ID") @PathVariable Long fileId) {
        
        File file = fileRepository.findById(fileId)
                .orElseThrow(() -> new ResourceNotFoundException("文件不存在"));
        
        try {
            Path filePath = Paths.get(file.getFilePath());
            Resource resource = new UrlResource(filePath.toUri());
            
            if (!resource.exists() || !resource.isReadable()) {
                throw new ResourceNotFoundException("文件不存在或不可读");
            }
            
            // 确定内容类型
            String contentType = Files.probeContentType(filePath);
            if (contentType == null) {
                contentType = "application/octet-stream";
            }
            
            return ResponseEntity.ok()
                    .contentType(MediaType.parseMediaType(contentType))
                    .header(HttpHeaders.CONTENT_DISPOSITION, 
                            "attachment; filename=\"" + file.getOriginalName() + "\"")
                    .body(resource);
                    
        } catch (MalformedURLException e) {
            log.error("文件下载失败", e);
            throw new BusinessException("文件下载失败");
        } catch (IOException e) {
            log.error("文件类型检测失败", e);
            throw new BusinessException("文件下载失败");
        }
    }
    
    /**
     * 获取文件列表
     */
    @Operation(summary = "获取文件列表", description = "获取当前用户的文件列表")
    @GetMapping
    public Result<PageResult<FileDTO>> getFiles(
            @Parameter(description = "页码") @RequestParam(defaultValue = "1") int page,
            @Parameter(description = "每页数量") @RequestParam(defaultValue = "10") int size,
            @Parameter(description = "文件类型") @RequestParam(required = false) String fileType) {
        
        Long currentUserId = SecurityUtils.getCurrentUserId();
        if (currentUserId == null) {
            throw new BusinessException("用户未登录");
        }
        
        Pageable pageable = PageRequest.of(page - 1, size, Sort.by("createTime").descending());
        Page<File> filePage;
        
        if (fileType != null && !fileType.isEmpty()) {
            // 根据文件类型过滤
            filePage = fileRepository.findByFileType(fileType, pageable);
        } else {
            // 获取当前用户的所有文件
            filePage = fileRepository.findByUserId(currentUserId, pageable);
        }
        
        List<FileDTO> fileDTOs = filePage.getContent().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
        
        return Result.success("获取成功", PageResult.of(fileDTOs, filePage.getTotalElements(), page, size));
    }
    
    /**
     * 获取文件详情
     */
    @Operation(summary = "获取文件详情", description = "获取指定文件的详细信息")
    @GetMapping("/{fileId}")
    public Result<FileDTO> getFileById(@Parameter(description = "文件ID") @PathVariable Long fileId) {
        
        File file = fileRepository.findById(fileId)
                .orElseThrow(() -> new ResourceNotFoundException("文件不存在"));
        
        return Result.success("获取成功", convertToDTO(file));
    }
    
    /**
     * 删除文件
     */
    @Operation(summary = "删除文件", description = "删除指定的文件")
    @DeleteMapping("/{fileId}")
    @Transactional
    public Result<Void> deleteFile(@Parameter(description = "文件ID") @PathVariable Long fileId) {
        
        Long currentUserId = SecurityUtils.getCurrentUserId();
        if (currentUserId == null) {
            throw new BusinessException("用户未登录");
        }
        
        File file = fileRepository.findById(fileId)
                .orElseThrow(() -> new ResourceNotFoundException("文件不存在"));
        
        // 检查权限
        if (!file.getUserId().equals(currentUserId) && !SecurityUtils.isAdmin()) {
            throw new BusinessException("无权限删除此文件");
        }
        
        try {
            // 删除物理文件
            Path filePath = Paths.get(file.getFilePath());
            Files.deleteIfExists(filePath);
            
            // 删除数据库记录
            fileRepository.delete(file);
            
            log.info("文件删除成功: {}", file.getFilename());
            
            return Result.success("文件删除成功");
            
        } catch (IOException e) {
            log.error("删除物理文件失败", e);
            // 即使物理文件删除失败，也删除数据库记录
            fileRepository.delete(file);
            return Result.success("文件删除成功");
        }
    }
    
    /**
     * 获取图片文件列表
     */
    @Operation(summary = "获取图片文件", description = "获取图片类型的文件列表")
    @GetMapping("/images")
    public Result<PageResult<FileDTO>> getImageFiles(
            @Parameter(description = "页码") @RequestParam(defaultValue = "1") int page,
            @Parameter(description = "每页数量") @RequestParam(defaultValue = "10") int size) {
        
        Pageable pageable = PageRequest.of(page - 1, size, Sort.by("createTime").descending());
        Page<File> filePage = fileRepository.findImageFiles(pageable);
        
        List<FileDTO> fileDTOs = filePage.getContent().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
        
        return Result.success("获取成功", PageResult.of(fileDTOs, filePage.getTotalElements(), page, size));
    }
    
    /**
     * 获取用户上传统计
     */
    @Operation(summary = "获取上传统计", description = "获取当前用户的文件上传统计信息")
    @GetMapping("/statistics")
    public Result<FileStatistics> getFileStatistics() {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        if (currentUserId == null) {
            throw new BusinessException("用户未登录");
        }
        
        long fileCount = fileRepository.countByUserId(currentUserId);
        Long totalSize = fileRepository.sumFileSizeByUserId(currentUserId);
        
        FileStatistics statistics = FileStatistics.builder()
                .fileCount(fileCount)
                .totalSize(totalSize != null ? totalSize : 0L)
                .maxFileSize(maxFileSize)
                .build();
        
        return Result.success("获取成功", statistics);
    }
    
    /**
     * 获取文件类型
     */
    private String getFileType(String fileExtension) {
        if (fileExtension == null || fileExtension.isEmpty()) {
            return "unknown";
        }
        
        String ext = fileExtension.toLowerCase().substring(1); // 去掉点号
        
        // 图片类型
        if (List.of("jpg", "jpeg", "png", "gif", "bmp", "webp").contains(ext)) {
            return "image";
        }
        // 文档类型
        if (List.of("pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt").contains(ext)) {
            return "document";
        }
        // 视频类型
        if (List.of("mp4", "avi", "mov", "wmv", "flv", "mkv").contains(ext)) {
            return "video";
        }
        // 音频类型
        if (List.of("mp3", "wav", "flac", "aac", "ogg").contains(ext)) {
            return "audio";
        }
        
        return ext;
    }
    
    /**
     * 转换为DTO
     */
    private FileDTO convertToDTO(File file) {
        FileDTO dto = FileDTO.builder()
                .id(file.getId())
                .fileName(file.getFilename())
                .originalName(file.getOriginalName())
                .fileType(file.getFileType())
                .fileSize(file.getFileSize())
                .filePath(file.getFilePath())
                .fileUrl("/api/files/download/" + file.getId())
                .isPublic(true) // 简化实现，默认为公开
                .createdAt(file.getCreateTime())
                .build();
        
        // 上传者信息
        userRepository.findById(file.getUserId()).ifPresent(user -> {
            FileDTO.UploaderInfo uploaderInfo = FileDTO.UploaderInfo.builder()
                    .id(user.getId())
                    .username(user.getUsername())
                    .nickname(user.getProfile() != null ? user.getProfile().getNickname() : null)
                    .build();
            dto.setUploader(uploaderInfo);
        });
        
        return dto;
    }
    
    /**
     * 文件统计信息
     */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class FileStatistics {
        private Long fileCount;
        private Long totalSize;
        private Long maxFileSize;
    }
} 